# -*- coding: UTF-8 -*-
from mutator import blobmuta
from mutator import stringmuta
from mutator import binarymuta
import random
import bluetooth
import time


class Avctp:
    # Non-Fragmented AVCTP Message
    TRANSACTION_LABEL = '' # bits 7-4, 4bits provided by the application
    PACKET_TYPE = '' # bits 3 and 2 00=transmitted in a single L2CAP packet
    C_R = '' # bit 1 (0=command frame, 1=response frame) provided by the application
    IPID = '' # bit 1 (0=command frame, 1=response frame)
    PID = '' # 16bits UUID(service class defined for this profile in the Bluetooth Assigned Numbers document)
    # -------------------------------------------------------------------------------------------------------
    # Fragmented AVCTP Message

    def __init__(self, addr):
        self.addr = addr

    # fuzz TRANSACTION_LABEL+PACKET_TYPE+C_R+IPID
    def fuzz_non_fragmented1(self):
        tpci = '\x01\x58'
        pid = '\x00\x0F'
        rand = random.Random()
        r_flag = random.randint(1, 12)
        tpci = self._fs(tpci, rand, r_flag)
        msg = tpci + pid
        network_code = self.send_avctp(msg)
        return [network_code, r_flag, msg]
        # return [network_code, r_flag, msg, tpci, pid]

    # fuzz PID
    def fuzz_not_fragmented2(self):
        tpci = '\x11\x0F'
        pid = '\x00\x1A'
        rand = random.Random()
        r_flag = random.randint(1, 12)
        pid = self._fs(pid, rand, r_flag)
        msg = tpci + pid
        network_code = self.send_avctp(msg)
        return [network_code, r_flag, msg]
        # return [network_code, r_flag, msg, tpci, pid]

    def send_avctp(self, msg):
        psm = 23 # 0x0017
        sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
        sock.settimeout(5)
        try:
            sock.connect((self.addr, psm))
        except:
            return 1
        try:
            # 同一个包发5次
            for i in range(0, 5):
                sock.send(msg)
        except:
            return 2
        return 0

    def avctp_random_fuzz(self):
        i = random.randint(0, 1)
        if i == 0:
            return self.fuzz_non_fragmented1()
        if i == 1:
            return self.fuzz_not_fragmented2()

    def _fs(self, data, rand, flag):

        if (flag == 0):
            return data

        if (flag == 1):
            s = stringmuta.StringCaseMutator()
            return s.mutationRandomCase(data)

        if (flag == 2):
            s = stringmuta.UnicodeBomMutator()
            return s.randomMutation(rand)

        if (flag == 3):
            s = stringmuta.UnicodeBadUtf8Mutator()
            return s.randomMutation(rand)

        if (flag == 4):
            b = blobmuta.DWORDSliderMutator(data)
            return b.randomMutation(data, rand)

        if (flag == 5):
            b = blobmuta.BitFlipperMutator(data)
            return b.randomMutation(data, rand)

        b = blobmuta.BlobMutator(data)
        if (flag == 6):
            return ""  # 返回空字符串

        if (flag == 7):
            return b.changeReduceBuffer(data, rand)

        if (flag == 8):
            return b.changeChangeRangeSpecial(data, rand)

        if (flag == 9):
            return b.changeExpandBuffer(data, rand)

        if (flag == 10):
            return b.changeNullRange(data, rand)

        if (flag == 11):
            return b.changeChangeRange(data, rand)

        if (flag == 12):
            h = binarymuta.Handler()
            return h.Fuzzit(data)

if __name__ == '__main__':
    addr = 'A4:50:46:A9:5C:DE'
    av = Avctp(addr)
    for i in range(0, 10):
        time.sleep(0.5)
        print av.fuzz_non_fragmented1()
